package cn.bugstack.springframework.context.event;

import cn.bugstack.springframework.beans.BeansException;
import cn.bugstack.springframework.beans.factory.BeanFactory;
import cn.bugstack.springframework.beans.factory.BeanFactoryAware;
import cn.bugstack.springframework.context.ApplicationEvent;
import cn.bugstack.springframework.context.ApplicationListener;
import cn.bugstack.springframework.util.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * 抽象的应用事件广播类，实现了应用事件广播器接口和BeanFactoryAware接口。
 * 用于管理应用事件的监听器，并提供事件的广播机制。
 */
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {

    /**
     * 用于存储应用程序事件监听器的集合。
     * 这是一个链接哈希集（LinkedHashSet），它保持了元素的插入顺序，
     * 同时提供了快速的查找和插入操作。
     */
    public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();

    private BeanFactory beanFactory;

    /**
     * 添加一个应用事件监听器。
     * @param listener 要添加的监听器
     */
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
    }

    /**
     * 移除一个应用事件监听器。
     * @param listener 要移除的监听器
     */
    @Override
    public void removeApplicationListener(ApplicationListener<?> listener) {
        applicationListeners.remove(listener);
    }

    /**
     * 设置BeanFactory，用于获取应用实例。
     * @param beanFactory BeanFactory实例
     */
    @Override
    public final void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 根据事件类型获取监听此事件的监听器集合。
     * @param event 事件对象，用于提前排除不匹配的监听器。
     * @return 监听此事件的监听器集合
     */
    protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
        LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
        for (ApplicationListener<ApplicationEvent> listener : applicationListeners) {
            if (supportsEvent(listener, event)) {
                allListeners.add(listener);
            }
        }
        return allListeners;
    }

    /**
     * 判断给定的监听器是否支持指定的事件。
     * 这段代码的作用是判断给定的 ApplicationListener 是否支持处理特定类型的事件。
     * 它通过检查监听器实现的泛型接口 ApplicationListener<ApplicationEvent>，从中获取到实际的事件类型参数，并与要处理的事件类型进行匹配。
     *
     * @param applicationListener 待判断的监听器
     * @param event 指定的事件
     * @return 如果监听器支持此事件，则返回true；否则返回false。
     */
    protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {

        // Class<? extends ApplicationListener> 表示一个 Class 对象，该对象是 ApplicationListener 或其子类的类对象。
        // 这种写法是 Java 泛型中的通配符类型，其中 ? extends ApplicationListener 表示可以是 ApplicationListener 的任何子类，
        // 获取监听器的类对象。
        Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();

        // 如果监听器是CGLIB代理类，则获取其父类作为目标类。
        Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ? listenerClass.getSuperclass() : listenerClass;
        // 获取目标类实现的第一个泛型接口，即 ApplicationListener 接口。
        Type genericInterface = targetClass.getGenericInterfaces()[0];

        // 从泛型接口中获取实际的事件类型参数。
        Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
        String className = actualTypeArgument.getTypeName();
        Class<?> eventClassName;
        // 将事件类型参数的类名转换为 Class 对象。
        try {
            eventClassName = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new BeansException("wrong event class name: " + className);
        }

        // 判断给定的事件类型是否是实际事件类型参数的子类或者相同类型，即判断事件类型是否匹配。
        // 如果事件类型匹配，则返回 true，表示该监听器支持处理该类型的事件；否则返回 false。
        return eventClassName.isAssignableFrom(event.getClass());
    }

}
